# coding:utf-8

import codecs;

"""

@summary: 数据类型

"""
class MapsType:
    ObjectValue = 0;
    NumberValue = 1;
    StringValue = 2;
    BitArray = 3;    
    
    pass

"""
数据头信息
"""
class MapsHead:
    
    ValueNumber1 = 2;
    ValueNumber2 = 3;
    ValueNumber3 = 4;
    ValueNumber4 = 5;
    ValueNumber5 = 6;
    ValueNumber6 = 7;
    ValueNumber7 = 8;
    ValueNumber8 = 9;
    ValueString = 10;
    ValueBitArray = 11;
    Down = 13;
    Up = 14;
    End = 15;
    
    pass

"""
@summary:消息快
"""
class MapsValue:
    
    def __init__(self, num=None, Str=None, DEFAULT=True, maptype=None, by=None):
        
        if(DEFAULT):
            self.int32 = num;
            self.str = Str;
            if(num != None):
                self.mapsType = MapsType.NumberValue;
            elif(Str != None):
                self.mapsType = MapsType.StringValue;
            else:
                self.mapsType = MapsType.ObjectValue;
            self.dictStr = {};
            self.dictInt = {};
            self.mapsHead = 0;
            
            pass
        else:
            
            self.mapsType = maptype;
            
            if(maptype == MapsType.NumberValue):
                self.int32 = self.ByteToInt(by);
            elif(maptype == MapsType.StringValue):
                self.str = self.ByteToString(by);
            
            pass
        
        pass
    
    def StringToByte(self, st):
        
        cod = codecs.lookup("utf-8");
        bu = cod.encode(st);
        
        return bytearray(bu[0]);
        
        pass
    
    def ByteToString(self, b):
    
        return str(b);
    
        pass
    
    """
    @summary: int 转 byte[]
    """
    def IntToByte(self, num):
        rt = bytearray(4);
        if(num < 0):
            num = -num;
            rt[0] = (((num << 1) & 0xff) | 1);
            rt[1] = ((num >> 7) & 0xff);
            rt[2] = ((num >> 15) & 0xff);
            rt[3] = ((num >> 23) & 0xff);
        else:
            rt[0] = ((num << 1) & 0xff);
            rt[1] = ((num >> 7) & 0xff);
            rt[2] = ((num >> 15) & 0xff);
            rt[3] = ((num >> 23) & 0xff);
        ln = 4;
        while(ln > 1):
            
            if(rt[ln - 1] != 0):
                break;
            ln -= 1;
            
            pass
        rtnew = bytearray(ln);
        
        for i in range(ln):
            rtnew[i] = rt[i];
            pass
        
        return rtnew;
    
        pass

    """
    @summary:byte[]转int
    """
    def ByteToInt(self, i):
        rt = 0;
        negative = ((i[0] & 1) == 1);
        ln = len(i);
        if(ln == 1):
            rt = i[0] >> 1;
            pass
        elif(ln == 2):
            rt = i[0] >> 1 | i[1] << 7;
            pass
        elif(ln == 3):
            rt = i[0] >> 1 | i[1] << 7 | i[2] << 15;
            pass
        else:
            rt = i[0] >> 1 | i[1] << 7 | i[2] << 15 | i[3] << 23;
            pass
        
        if(negative):
            return -rt;
        else:
            return rt;
        
        pass
    
    def IntToMapsHead(self, num):
        
        num = num + 1;
        if(num == 2):
            return MapsHead.ValueNumber1
            pass
        elif(num == 3):
            return MapsHead.ValueNumber2
            pass
        elif(num == 4):
            return MapsHead.ValueNumber3
            pass
        elif(num == 5):
            return MapsHead.ValueNumber4
            pass
        elif(num == 6):
            return MapsHead.ValueNumber5
            pass
        elif(num == 7):
            return MapsHead.ValueNumber6
            pass
        elif(num == 8):
            return MapsHead.ValueNumber7
            pass
        elif(num == 9):
            return MapsHead.ValueNumber8
            pass
        
        pass
    
    def ToStream(self):
        
        if(self.mapsType == MapsType.NumberValue):
            rt = self.IntToByte(self.int32);
            self.mapsHead = self.IntToMapsHead(len(rt));
            return rt;
        
            pass
        elif(self.mapsType == MapsType.StringValue):
            rt = self.StringToByte(self.str);
            rt.append(1);
            self.mapsHead = MapsHead.ValueString;
            return rt;
                
            pass
        
        pass
    
    pass


"""
@summary: 消息对象
"""
class ProtocolValue:
    
    def __init__(self):
        self.mv = MapsValue();
        pass
    
    def AddIntKey(self, key, mv):
        
        self.mv.dictInt[key] = mv;
        
        pass
    
    def AddStringKey(self, key, mv):
        
        self.mv.dictStr[key] = mv;
        
        pass
    
    """
    @summary: int 转 byte[]
    """
    def IntToByte(self, num):
        rt = bytearray(4);
        if(num < 0):
            num = -num;
            rt[0] = (((num << 1) & 0xff) | 1);
            rt[1] = ((num >> 7) & 0xff);
            rt[2] = ((num >> 15) & 0xff);
            rt[3] = ((num >> 23) & 0xff);
        else:
            rt[0] = ((num << 1) & 0xff);
            rt[1] = ((num >> 7) & 0xff);
            rt[2] = ((num >> 15) & 0xff);
            rt[3] = ((num >> 23) & 0xff);
            
        return rt;
    
        pass

    
    def ValueToStream(self, mv, listHead, bodyStream):
        
        if(mv.mapsType == MapsType.ObjectValue):
            
            listHead.append(MapsHead.Down);
            
            self.ObjectToStream(mv, listHead, bodyStream);
            
            listHead.append(MapsHead.Up);
            
            pass
        else:
            
            mb = mv.ToStream();
                
            for i in range(len(mb)):
                
                bodyStream.append(mb[i]);
                
                pass
            
            listHead.append(mv.mapsHead);
            
            
            pass
        
        pass
    
    """
    @summary:转换位字节
    """
    def ObjectToStream(self, mv, listHead, bodyStream):
        
        if(len(mv.dictInt) > 0):
            
            for ky in mv.dictInt:
                
                # key
                m = MapsValue(num=ky);
                mb = m.ToStream();
                
                for i in range(len(mb)):
                    bodyStream.append(mb[i]);
                    
                    pass
                
                listHead.append(m.mapsHead);
                
                # value
                value = mv.dictInt[ky];
                
                self.ValueToStream(value, listHead, bodyStream);
                
                pass
            
            pass
        
        if(len(mv.dictStr) > 0):
            
            for ky in mv.dictStr:
                
                # key
                m = MapsValue(Str=ky);
                mb = m.ToStream();
                
                for i in range(len(mb)):
                    bodyStream.append(mb[i]);
                    
                    pass
                
                listHead.append(m.mapsHead);
                
                # value
                value = mv.dictStr[ky];
                
                self.ValueToStream(value, listHead, bodyStream);
                
                pass
            
            pass
        
        pass
    
    def ToStream(self):
        
        listHead = [];
        bodyStream = bytearray();
        headStream = bytearray();
        
        content = bytearray();
        
        self.ObjectToStream(self.mv, listHead, bodyStream);
        lt = len(listHead);
        l = (lt >> 1) << 1;
        
        for i in range(l):
            if(i+2<=l):
                if(i % 2 == 0):
                    
                    headStream.append((listHead[i] << 4) | listHead[i + 1]);
                    
                    pass
                pass
            else:
                break;
            
                pass
            
            pass
        
        if(lt != l):
            headStream.append((listHead[lt-1] << 4) | 0xff);
        
        if(lt == l):
            headStream.append(0xff);
            pass
        
        for i in range(len(bodyStream)):
            headStream.append(bodyStream[i]);
        
        h = self.IntToByte(len(headStream));
        
        for i in range(len(h)):
            content.append(h[i]);
            
        for i in range(len(headStream)):
            content.append(headStream[i]);
            
        print list(content);
        
        pass
    
    pass

if(__name__ == "__main__"):
    
    mvpv = ProtocolValue();
    
    mvpv.AddIntKey(1, MapsValue(Str="abc"));
    mvpv.AddIntKey(2, MapsValue(num=2));
    mvpv.AddStringKey("a", MapsValue(Str="def"));
    
    mv = MapsValue();
    mv.dictInt[1] = MapsValue(Str="abc");
    mv.dictStr["a"] = MapsValue(Str="a");
    
    mvpv.AddIntKey(3, mv);
    
    mvpv.ToStream();
    
    
    pass
